
//
//  ZXY_DownloadAction.m
//  DownLoadTest
//
//  Created by 宇周 on 15/8/24.
//  Copyright (c) 2015年 宇周. All rights reserved.
//

#import "ZXY_DownloadAction.h"
#import "AppDelegate.h"
#import "ZXY_DownloadActionItem.h"
#import "ZXY_DownLoadUtility.h"

@interface ZXY_DownloadAction()<NSURLSessionDelegate , NSURLSessionDownloadDelegate>
{
    
}
@property(nonatomic , strong)ZXY_DownItem *currentItem;
//@property(nonatomic , strong)NSMutableArray *allTaskInfo;
@property(assign)long long currentSize;
@property(assign)long long sumSize;
@property(nonatomic , strong)NSMutableArray *allTask;

@property(nonatomic , strong)NSString *headerString;
@end

@implementation ZXY_DownloadAction

static NSString *sessionID = @"com.duostec.DLNetSchool.ZXYDownload";

static ZXY_DownloadAction *SINGLETON = nil;

static bool isFirstAccess = YES;

#pragma mark - Public Method

+ (id)sharedInstance
{
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        isFirstAccess = NO;
        SINGLETON = [[super allocWithZone:NULL] init];
    });
    
    return SINGLETON;
}

#pragma mark - Life Cycle

+ (id) allocWithZone:(NSZone *)zone
{
    return [self sharedInstance];
}

+ (id)copyWithZone:(struct _NSZone *)zone
{
    return [self sharedInstance];
}

+ (id)mutableCopyWithZone:(struct _NSZone *)zone
{
    return [self sharedInstance];
}

- (id)copy
{
    return [[ZXY_DownloadAction alloc] init];
}

- (id)mutableCopy
{
    return [[ZXY_DownloadAction alloc] init];
}

- (id) init
{
    if(SINGLETON){
        return SINGLETON;
    }
    if (isFirstAccess) {
        [self doesNotRecognizeSelector:_cmd];
    }
    self = [super init];
    if(self)
    {
        self.downLoadSession = [self backGroundMethod];
        self.allTask         = [[NSMutableArray alloc] init];
    }
    return self;
}

- (NSURLSession *)backGroundMethod
{
    static dispatch_once_t dispatchOne ;
    static NSURLSession *session = nil;
    dispatch_once(&dispatchOne, ^{
        NSURLSessionConfiguration *config = [NSURLSessionConfiguration backgroundSessionConfigurationWithIdentifier:sessionID];
        config.allowsCellularAccess = YES;
        session = [NSURLSession sessionWithConfiguration:config delegate:self delegateQueue:nil];
        
        
    });
    return session;
}

- (NSArray *)allCurrentInSessionTask
{
    dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
    __block NSArray *allTaskBlock = nil;
    [_downLoadSession getTasksWithCompletionHandler:^(NSArray *dataTasks, NSArray *uploadTasks, NSArray *downloadTasks) {
        allTaskBlock = downloadTasks;
        dispatch_semaphore_signal(semaphore);
    }];
    dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
    return allTaskBlock;
}

#pragma mark - ------- 实力话结束 --------

- (void)addLoadItem:(ZXY_DownItem *)item
{
    [self addItemToActionItemWithAddTask:item];
//    [self achieveOtherTaskFromSession];
}

/**
 *  增加一个可供下载的item
 *
 *  @param item 下载item
 */
- (void)addItemToActionItemWithAddTask:(ZXY_DownItem *)item
{
    
    if(![self validateItem:item])
    {
        return;
    }
    BOOL isContainDownKey = [ZXY_DownLoadUtility itemFromFileWithKey:item.downKey] == nil ? NO : YES;
    if(!isContainDownKey)
    {
        ZXY_DownloadActionItem *itemA = [[ZXY_DownloadActionItem alloc] init];
        
        itemA.item = item;
        if([self isCurrentSessionContainWithKey:item.downKey])
        {
            NSURLSessionDownloadTask *task = [self taskWithKey:item.downKey];
            
            task.taskDescription = item.downKey;
            itemA.task = task;
            dispatch_async(dispatch_get_main_queue(), ^{
                [task resume];
                
            });
        }
        else
        {
            NSURL *url = [NSURL URLWithString:[item.downPath stringByReplacingOccurrencesOfString:@" " withString:@"%20"]];
            NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
            #warning 可能需要头文件信息
            [request addValue:@"http://www.acourse.net/NFE/" forHTTPHeaderField:@"REFERER"];
            NSURLSessionDownloadTask *task = [self.downLoadSession downloadTaskWithRequest:request];
            task.taskDescription = item.downKey;
            itemA.task = task;
            dispatch_async(dispatch_get_main_queue(), ^{
                [task resume];
                
            });
        }
        [ZXY_DownLoadUtility writeActionItemToFile:item];
        if(![self isAllInfoContainKey:item.downKey])
        {
            [self.allTask addObject:itemA];
        }
    }
    else
    {
        ZXY_DownItem *currentItem = [ZXY_DownLoadUtility itemFromFileWithKey:item.downKey];
        ZXY_DownloadActionItem *itemA = [[ZXY_DownloadActionItem alloc] init];
        itemA.item = currentItem;
        if(![self taskWithKey:currentItem.downKey])
        {
            NSURLSessionDownloadTask *task ;
            
            NSURL *url = [NSURL URLWithString:[item.downPath stringByReplacingOccurrencesOfString:@" " withString:@"%20"]];
            NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
            [request addValue:@"http://www.acourse.net/NFE/" forHTTPHeaderField:@"REFERER"];

            task = [self.downLoadSession downloadTaskWithRequest:request];
            task.taskDescription = currentItem.downKey;
            itemA.task = task;
            dispatch_async(dispatch_get_main_queue(), ^{
                [task resume];
                
            });
        }
        else
        {
            NSURLSessionDownloadTask *task = [self taskWithKey:currentItem.downKey];
            if([item.status isEqualToString:@"3"])
            {
                __weak ZXY_DownloadAction *weakSelf = self;
                [task cancelByProducingResumeData:^(NSData *resumeData) {
                    if(resumeData)
                    {
                        NSURL *url = [NSURL URLWithString:[item.downPath stringByReplacingOccurrencesOfString:@" " withString:@"%20"]];
                        NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
                        NSString *headerField = [NSString stringWithFormat:@"bytes=%lu-",(unsigned long)resumeData.length];
                        [request setValue:headerField forHTTPHeaderField:@"range"];
                        NSURLSessionDownloadTask *taskBlock = [weakSelf.downLoadSession downloadTaskWithRequest:request];
                        taskBlock.taskDescription = item.downKey;
                        itemA.task = taskBlock;
                        [taskBlock resume];
                        [ZXY_DownLoadUtility setStatusForKey:item.downKey andStatus:@"0"];
                        if(![weakSelf isAllInfoContainKey:item.downKey])
                        {
                            [weakSelf.allTask addObject:itemA];
                        }
                    }
                }];
            }
            else
            {
                task.taskDescription = currentItem.downKey;
                itemA.task = task;
                dispatch_async(dispatch_get_main_queue(), ^{
                    [task resume];
                    
                });
            }
        }
        if(![self isAllInfoContainKey:item.downKey])
        {
            [self.allTask addObject:itemA];
        }
    }
}


- (BOOL)isCurrentSessionContainWithKey:(NSString *)key
{
    for(NSURLSessionDownloadTask *task in [self allCurrentInSessionTask])
    {
        if([key isEqualToString:task.taskDescription])
        {
            return YES;
        }
    }
    return NO;
}

- (NSURLSessionDownloadTask *)taskWithKey: (NSString *)key
{
    for(NSURLSessionDownloadTask *task in [self allCurrentInSessionTask])
    {
        if([key isEqualToString:task.taskDescription])
        {
            return task;
        }
    }
    return nil;

}


- (void)pauseItem:(ZXY_DownItem *)item
{
    
    for(NSURLSessionDownloadTask *one in [self allCurrentInSessionTask])
    {
        if([item.downKey isEqualToString:one.taskDescription])
        {
            if(one.state == NSURLSessionTaskStateRunning)
            {
                [one suspend];
            }
            else
            {
                [one cancel];
            }
        }
    }
}

- (void)cancelItem:(ZXY_DownItem *)item
{
    for(NSURLSessionDownloadTask *one in [self allCurrentInSessionTask])
    {
        if([item.downKey isEqualToString:one.taskDescription])
        {
            [one cancel];
        }
    }
}

- (void)changeOrderMakeFirst:(ZXY_DownItem *)item
{
    [_downLoadSession getTasksWithCompletionHandler:^(NSArray *dataTasks, NSArray *uploadTasks, NSArray *downloadTasks) {
        for(NSURLSessionDownloadTask *one in downloadTasks)
        {
            if([one.taskDescription isEqualToString:item.downKey])
            {
                [one resume];
            }
        }
    }];

}

- (void)cancelDown
{
    [self.downLoadSession invalidateAndCancel];
    if(self.delegate)
    {
        [self.delegate downLoadCancelSession];
    }
}

#pragma mark - 下载代理


- (void)URLSession:(NSURLSession *)session didBecomeInvalidWithError:(NSError *)error
{
    if(self.delegate)
    {
        [self.delegate downLoadCancelItem:nil];
    }
}

- (void)URLSessionDidFinishEventsForBackgroundURLSession:(NSURLSession *)session
{
    AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
    if (appDelegate.backGroundURLSessionCompleteHandle) {
        void (^completionHandler)() = appDelegate.backGroundURLSessionCompleteHandle;
        completionHandler(NSURLSessionResponseAllow);
        NSLog(@"back");
        appDelegate.backGroundURLSessionCompleteHandle = nil;
    }
}

- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didFinishDownloadingToURL:(NSURL *)location
{
    __weak ZXY_DownloadAction *weakSelf = self;
    
    ZXY_DownItem *item = [self itemFromActionTask:downloadTask];
    if(item == nil)
    {
        item = [ZXY_DownLoadUtility itemFromFileWithKey:downloadTask.taskDescription];
    }
    
    

    NSString *filepath = item.downSavePath;
    if(filepath)
    {
        if([[NSFileManager defaultManager] fileExistsAtPath:filepath isDirectory:nil])
        {
            [[NSFileManager defaultManager] removeItemAtPath:filepath error:nil];
        }
        NSError *fileError = nil;
        [[NSFileManager defaultManager] moveItemAtURL:location toURL:[[NSURL alloc] initFileURLWithPath:filepath] error:&fileError];
        if(fileError)
        {
            NSLog(@"file Error is %@",fileError);
            dispatch_async(dispatch_get_main_queue(), ^{
                [weakSelf.delegate downLoadFail:[weakSelf itemFromActionTask:downloadTask]];
                [ZXY_DownLoadUtility removeActionItemFromFileWithKey:downloadTask.taskDescription];
                [weakSelf removeActionItemWithKey:downloadTask.taskDescription];
            });
        }
        else
        {
            dispatch_async(dispatch_get_main_queue(), ^{
                [weakSelf.delegate downLoadSuccess:[weakSelf itemFromActionTask:downloadTask]];
                [ZXY_DownLoadUtility removeActionItemFromFileWithKey:downloadTask.taskDescription];
                [weakSelf removeActionItemWithKey:downloadTask.taskDescription];
            });
        }
    }
}

- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didWriteData:(int64_t)bytesWritten totalBytesWritten:(int64_t)totalBytesWritten totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite
{
    if(totalBytesWritten == 0)
    {
        return;
    }
    if(self.delegate)
    {
        
        __weak ZXY_DownloadAction *weakSelf = self;
        dispatch_async(dispatch_get_main_queue(), ^{
            [weakSelf.delegate downLoadLength:totalBytesWritten andExpectLength:totalBytesExpectedToWrite aboutItem:[weakSelf itemFromActionTask:downloadTask]];
        });
        
    }
}

- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask
 didResumeAtOffset:(int64_t)fileOffset
expectedTotalBytes:(int64_t)expectedTotalBytes
{
    NSLog(@"file off set is %lld",fileOffset);
}

- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error
{
    ZXY_DownItem *item = [ZXY_DownLoadUtility itemFromFileWithKey:task.taskDescription];
    if(item == nil)
    {
        return;
    }
    if(error)
    {
        __weak ZXY_DownloadAction *weakSelf = self;
        dispatch_async(dispatch_get_main_queue(), ^{
            [weakSelf.delegate downLoadFail:[weakSelf itemFromActionTask:task]];
            [ZXY_DownLoadUtility removeActionItemFromFileWithKey:task.taskDescription];
            [weakSelf removeActionItemWithKey:task.taskDescription];
            [task cancel];
        });
    }
    
}

#pragma mark - 帮助方法
- (ZXY_DownItem *)itemFromActionTask:(NSURLSessionTask *)task
{
    ZXY_DownItem *item = [ZXY_DownLoadUtility itemFromFileWithKey:task.taskDescription];
    if(item)
    {
        return item;
    }
    return nil;
}

- (BOOL)containItem:(ZXY_DownItem *)item
{
    ZXY_DownItem *items = [ZXY_DownLoadUtility itemFromFileWithKey:item.downKey];
    
    if(items)
    {
        return YES;
    }
    return NO;
}

- (void)removeActionItemWithItem:(ZXY_DownItem *)item
{
    [self removeActionItemWithKey:item.downKey];
}

- (void)removeActionItemWithKey:(NSString *)key
{
    ZXY_DownloadActionItem *itemForDelete = nil;
    for(int i = 0 ; i < self.allTask.count ; i++)
    {
        ZXY_DownloadActionItem *item = self.allTask[i];
        if([item.task.taskDescription isEqualToString:key])
        {
            itemForDelete = item;
        }
    }
    if(itemForDelete)
    {
        [self.allTask removeObject:itemForDelete];
    }
    [ZXY_DownLoadUtility removeActionItemFromFileWithKey:key];
}

- (BOOL)isAllTaskContainTask:(NSURLSessionDownloadTask *)task
{
    for(ZXY_DownloadActionItem *one in self.allTask)
    {
        if([one.task.taskDescription isEqualToString:task.taskDescription])
        {
            return YES;
        }
    }
    return NO;
}

- (BOOL)isAllInfoContainKey:(NSString *)key
{
    for(ZXY_DownloadActionItem *one in self.allTask)
    {
        if([one.task.taskDescription isEqualToString:key])
        {
            return YES;
        }
    }
    return NO;

}


- (BOOL)validateItem:(ZXY_DownItem *)item
{
    BOOL isValidate = YES;
    NSString *validateString = @"";
    if(item.downKey == nil)
    {
        isValidate = NO;
        validateString = @"downKey 不能为空";
    }
    else if (item.downPath == nil)
    {
        isValidate = NO;
        validateString = @"downPath 不能为空";
    }
    else if (item.downSavePath == nil)
    {
        isValidate = NO;
        validateString = @"downSavePath 不能为空";
    }
    
    if(!isValidate)
    {
        NSLog(@"error item reason : %@",validateString);
        if(self.delegate)
        {
            if([self.delegate respondsToSelector:@selector(downLoadFail:)])
            {
                [self.delegate downLoadFail:item];
            }
        }

    }
    return isValidate;
    
    
}

@end
